package com.liangtian.mdm.base.controller;

import com.liangtian.mdm.base.authentication.JWTToken;
import com.liangtian.mdm.base.authentication.JWTUtil;
import com.liangtian.mdm.base.constants.MdmConstant;
import com.liangtian.mdm.base.constants.ResultCode;
import com.liangtian.mdm.base.manager.UserManager;
import com.liangtian.mdm.base.model.ActiveUser;
import com.liangtian.mdm.base.model.LoginUser;
import com.liangtian.mdm.base.properties.MdmProperties;
import com.liangtian.mdm.base.response.BaseResponse;
import com.liangtian.mdm.base.utils.*;
import com.liangtian.mdm.system.user.model.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static com.liangtian.mdm.base.constants.MdmConstant.TOKEN_CACHE_PREFIX;

/**
 * 登录注册
 *
 * @author Qi
 */
@Slf4j
@Validated
@RestController
public class LoginController extends BaseController {

    @Autowired
    private UserManager userManager;
    @Autowired
    private MdmProperties properties;

    public static void main(String[] args) {

        String userPassword = MD5Util.encrypt("admin", "b81d8955ae252dc0f91e84a91eda55b7");
        System.out.println(userPassword);

    }

    /**
     * @param loginUser 登录用户
     *      userAccount  用户帐号
     *      userPassword 用户密码
     * @return 登陆结果
     */
    @ResponseBody
    @PostMapping(value = "/login")
    public BaseResponse login(@Validated @RequestBody LoginUser loginUser, HttpServletRequest request) throws Exception {
        String userAccount = loginUser.getUserAccount();
        String userPassword = loginUser.getUserPassword();
        userAccount = StringUtils.lowerCase(userAccount);
        try {
            userPassword = MD5Util.encrypt(userAccount, userPassword);
        } catch (Exception e) {
            log.error("解密密码过程出错", e);
            return new BaseResponse().fail(ResultCode.FAIL.getCode(), "解密密码过程出错");
        }

        SysUser user = this.userManager.getUser(userAccount);
        if (user == null || userPassword == null) {
            log.info("通过账号查找用户失败，userAccount：{}", userAccount);
            return BaseResponse.genResponse(ResultCode.USER_LOGIN_FAIL);
        }
        if (!StringUtils.equals(user.getUserPassword(), userPassword)) {
            return BaseResponse.genResponse(ResultCode.USER_LOGIN_FAIL);
        }
        //用户状态(0-导入（也叫批量未提交）W-待活动  D-批量已提交  T-待冻结    F-已冻结用户  A-活动用户  R-已驳回用户   N-待审核用户)
        if ("W".equals(user.getUserStatus()) || "0".equals(user.getUserStatus()) || "D".equals(user.getUserStatus())
                || "N".equals(user.getUserStatus()) || "R".equals(user.getUserStatus())) {
            return new BaseResponse().fail(ResultCode.USER_LOGIN_FAIL.getCode(), "账号未激活");
        } else if ("F".equals(user.getUserStatus())) {
            return new BaseResponse().fail(ResultCode.USER_LOGIN_FAIL.getCode(), "账号被冻结！");
        } else if ("T".equals(user.getUserStatus())) {
            return new BaseResponse().fail(ResultCode.USER_LOGIN_FAIL.getCode(), "账号已进入被冻结流程，不可用！");
        }
        String token = MdmUtil.encryptToken(JWTUtil.sign(userAccount, userPassword));
        LocalDateTime expireTime = LocalDateTime.now().plusSeconds(properties.getShiro().getJwtTimeOut());
        String expireTimeStr = DateUtils.formatFullTime(expireTime);
        JWTToken jwtToken = new JWTToken(token, expireTimeStr);

        String userId = this.saveTokenToCache(user, jwtToken, request);
        user.setId(userId);

        Map<String, Object> userInfo = this.generateUserInfo(jwtToken, user);
        return new BaseResponse().ok(userInfo);
    }

    /**
     * 生成前端需要的用户信息，包括：
     * 1. token 2.用户角色 3.用户权限
     *
     * @param token token
     * @param user  用户信息
     * @return UserInfo
     */
    private Map<String, Object> generateUserInfo(JWTToken token, SysUser user) {
        String userAccount = user.getUserAccount();
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("token", token.getToken());
        userInfo.put("exipreTime", token.getExipreAt());

        Set<String> roles = this.userManager.getUserRoles(userAccount);
        userInfo.put("roles", roles);

        Set<String> permissions = this.userManager.getUserPermissions(userAccount);
        userInfo.put("permissions", permissions);

        user.setUserPassword("it's a secret");
        userInfo.put("user", user);
        return userInfo;
    }

    private String saveTokenToCache(SysUser user, JWTToken token, HttpServletRequest request) throws Exception {
        String ip = IPUtil.getIpAddr(request);

        // 构建在线用户
        ActiveUser activeUser = new ActiveUser();
        activeUser.setUserAccount(user.getUserAccount());
        activeUser.setUserName(user.getUserName());
        activeUser.setIp(ip);
        activeUser.setToken(token.getToken());
        EhCacheUtils.setValue(MdmConstant.CACHE_NAMESPACE_TOKEN, TOKEN_CACHE_PREFIX + token.getToken() + "." + ip, token.getToken(), Math.toIntExact(properties.getShiro().getJwtTimeOut()));
        return activeUser.getId();
    }

    @GetMapping("/logout")
    public BaseResponse logout(HttpServletRequest request) {
        try {
            String token = request.getHeader(MdmConstant.AUTHENTICATION_TOKEN);
            // 删除对应的 token缓存
            String ip = IPUtil.getIpAddr(request);
            EhCacheUtils.removeElment(MdmConstant.CACHE_NAMESPACE_TOKEN, TOKEN_CACHE_PREFIX + token + "." + ip);
            return new BaseResponse().ok("退出系统成功");
        } catch (Exception e) {
            String message = "退出系统失败";
            log.error(message, e);
            return new BaseResponse().fail(ResultCode.FAIL.getCode(),message);
        }
    }

}
